package org.apache.ibatis.common.type;

import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @Name BaseTypeHandler
 * @Description: 类型处理器 [基类]
 * 描述信息：该类作为所有类型处理器的基类，定义了类型处理逻辑（模板）的框架。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-09 17:04:37
 **/
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {

    @Override
    public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            if (jdbcType == null) {
                String errorMsg = "JDBC 规范要求必须为所有可为 null 的参数指定 JdbcType。";
                throw new TypeException(errorMsg);
            }
            try {
                ps.setNull(i, jdbcType.TYPE_CODE);
            } catch (SQLException e) {
                String errorMsg = "无法为参数 #" + i + " - JdbcType [" + jdbcType + "] 设置 null 值。我们尝试为其设置一个不同的 JdbcType 类型或者一个不同的 jdbcTypeForNull 配置级属性，错误原因：" + e;
                throw new TypeException(errorMsg, e);
            }
        } else {
            try {
                setNonNullParameter(ps, i, parameter, jdbcType);
            } catch (Exception e) {
                String errorMsg = "无法为参数 #" + i + " - JdbcType [" + jdbcType + "] 设置 null 值。我们尝试为其设置一个不同的 JdbcType 类型或者一个不同的 jdbcTypeForNull 配置级属性，错误原因：" + e;
                throw new TypeException(errorMsg, e);
            }
        }
    }

    @Override
    public T getResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return getNullableResult(rs, columnName);
        } catch (Exception e) {
            String errorMsg = "无法从结果集 { + " + rs + "} 中获取指定的列 [" + columnName + "]，原因如下：" + e;
            throw new TypeException(errorMsg, e);
        }
    }

    @Override
    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return getNullableResult(rs, columnIndex);
        } catch (Exception e) {
            String errorMsg = "无法从结果集 { + " + rs + "} 中获取指定的列 [#" + columnIndex + "]，原因如下：" + e;
            throw new TypeException(errorMsg, e);
        }
    }

    @Override
    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return getNullableResult(cs, columnIndex);
        } catch (Exception e) {
            String errorMsg = "无法从回调语句 { + " + cs + "} 中获取指定的列 [#" + columnIndex + "]，原因如下：" + e;
            throw new TypeException(errorMsg, e);
        }
    }

    /**
     * 向 PreparedStatement 对象中的指定变量位置写入一个不为 null 的值。
     *
     * @param ps        预执行语句
     * @param i         变量位置
     * @param parameter 变量值
     * @param jdbcType  JDBC 变量类型
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-09 17:02:10
     */
    public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

    /**
     * 从 ResultSet 结果集中按照字段名称读取一条可能为 null 的数据。
     *
     * @param rs         结果集
     * @param columnName 字段名称
     * @return T 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-09 17:00:11
     */
    public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

    /**
     * 从 ResultSet 结果集中按照字段编号读取一条可能为 null 的数据。
     *
     * @param rs          结果集
     * @param columnIndex 字段编号
     * @return T 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-09 17:00:11
     */
    public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;

    /**
     * 从 CallableStatement 对象中按照字段编号读取一条可能为 null 的数据。
     *
     * @param cs          回调语句
     * @param columnIndex 字段编号
     * @return T 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-09 17:00:11
     */
    public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;

}

